#include "finsh_usart_config.h"



typedef struct 
{
    USART_TypeDef *instance; // register base address
}uart_base_t;

static uart_base_t uart_instance_tab[uart_ch_nums] = 
{
    { USART1},
    { USART2},
    { USART3},
};


typedef struct
{
	UART_HandleTypeDef huart[uart_ch_nums];
	fifo_t sfifo[uart_ch_nums];
	fifo_t rfifo[uart_ch_nums];
	
	uint8_t *tx_buf[uart_ch_nums];
	uint8_t *rx_buf[uart_ch_nums];
}stm_uart_t;
static stm_uart_t stm_uart_dev;
/**
  * @brief  The application entry point.
  * @retval int
  */
int fputc(int ch, FILE *f)
{
	//while ((__HAL_UART_GET_FLAG(&stm_uart_dev.huart[FINSH_PORT], UART_FLAG_TXE) == RESET))
	//{}
	//stm_uart_dev.huart[FINSH_PORT].Instance->DR = (uint8_t)ch;

	//return ch;

	finsh_uart_writes(FINSH_PORT,(uint8_t *)&ch,1);
	return (ch);
}

 /**
  */
int fgetc(FILE *f)
{
	//while (USART_GetFlagStatus(USART3, USART_FLAG_RXNE) == RESET);

	//return (int)USART_ReceiveData(USART3);
	
	return 0;
}

#pragma import(__use_no_semihosting)
 
struct __FILE
{
	int a;
};
 
FILE __stdout;
 
void _sys_exit(int x)
{
	
}


static void stm32_uart_init(uart_chx_e chx,struct uart_configure cfg)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */

  uart_base_t *uart_ins = (uart_base_t *)&uart_instance_tab[chx];
	stm_uart_t *uart = &stm_uart_dev;
	UART_HandleTypeDef *huart = &uart->huart[chx];
	
	//uart->huart[chx].Instance
	
  huart->Instance = uart_ins->instance;
  huart->Init.BaudRate = cfg.baud_rate;//115200;
  huart->Init.WordLength = cfg.word_length;
  huart->Init.StopBits = cfg.stop_bits;
	huart->Init.Parity = cfg.parity;
  huart->Init.Mode = cfg.mode;
  huart->Init.HwFlowCtl = cfg.hw_flow_ctl;
	huart->Init.OverSampling = cfg.over_sampling;
  if (HAL_UART_Init(huart) != HAL_OK)
  {
    //printf("xxxxxx HAL_UART_Init error.\r\n");
  }
  /* USER CODE BEGIN USART1_Init 2 */

  /* USER CODE END USART1_Init 2 */

}

/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(huart->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
		HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
		
		 /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
		
		__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);
		__HAL_UART_DISABLE_IT(huart,UART_IT_TXE);
		__HAL_UART_ENABLE_IT(huart,UART_IT_TC);

  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
  else if(huart->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspInit 0 */

  /* USER CODE END USART2_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART2_CLK_ENABLE();
  
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
		
		HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART2_IRQn);
		
		 /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
		
	__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);
	__HAL_UART_DISABLE_IT(huart,UART_IT_TXE);
	__HAL_UART_ENABLE_IT(huart,UART_IT_TC);

  /* USER CODE BEGIN USART2_MspInit 1 */

  /* USER CODE END USART2_MspInit 1 */
  }
  else if(huart->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspInit 0 */

  /* USER CODE END USART3_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART3_CLK_ENABLE();
  
    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**USART3 GPIO Configuration    
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
		
		HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART3_IRQn);
		
		 /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);

    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
		
	__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE);
	__HAL_UART_DISABLE_IT(huart,UART_IT_TXE);
	__HAL_UART_ENABLE_IT(huart,UART_IT_TC);
		
  /* USER CODE BEGIN USART3_MspInit 1 */

  /* USER CODE END USART3_MspInit 1 */
  }
	
}

/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
  if(huart->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();
  
    /**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
  else if(huart->Instance==USART2)
  {
  /* USER CODE BEGIN USART2_MspDeInit 0 */

  /* USER CODE END USART2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART2_CLK_DISABLE();
  
    /**USART2 GPIO Configuration    
    PA2     ------> USART2_TX
    PA3     ------> USART2_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

  /* USER CODE BEGIN USART2_MspDeInit 1 */

  /* USER CODE END USART2_MspDeInit 1 */
  }
  else if(huart->Instance==USART3)
  {
  /* USER CODE BEGIN USART3_MspDeInit 0 */

  /* USER CODE END USART3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART3_CLK_DISABLE();
  
    /**USART3 GPIO Configuration    
    PB10     ------> USART3_TX
    PB11     ------> USART3_RX 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);

  /* USER CODE BEGIN USART3_MspDeInit 1 */

  /* USER CODE END USART3_MspDeInit 1 */
  }

}

static uint8_t stm32_putc(uart_chx_e chx,fifo_t *fifo);
static uint8_t stm32_getc(fifo_t *fifo, uint8_t ch);
static void uart_isr(uart_chx_e chx)
{
	stm_uart_t *uart = &stm_uart_dev;
	
	if( __HAL_UART_GET_FLAG(&uart->huart[chx],UART_FLAG_RXNE) != RESET && __HAL_UART_GET_IT_SOURCE(&uart->huart[chx], UART_IT_RXNE) != RESET)
	{
		uint8_t ch = (uint8_t)(uart->huart[chx].Instance->DR &0x00FF);
		
		uint8_t sta = stm32_getc(&uart->rfifo[chx],ch);
		
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_IT_RXNE);
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_FLAG_RXNE);
	}
	else if(__HAL_UART_GET_FLAG(&uart->huart[chx],UART_FLAG_TXE) != RESET && __HAL_UART_GET_IT_SOURCE(&uart->huart[chx], UART_IT_TXE))
	{
		
		if( is_fifo_empty(&uart->sfifo[chx]) )
		{
			__HAL_UART_DISABLE_IT(&uart->huart[chx],UART_IT_TXE);
			__HAL_UART_DISABLE_IT(&uart->huart[chx],UART_IT_TC);
		}
		else
		{
			stm32_putc(chx,&uart->sfifo[chx]);
		}	
		
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_FLAG_TXE);
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_IT_TXE);
	}
	else if(__HAL_UART_GET_FLAG(&uart->huart[chx],UART_IT_TC) != RESET)
	{
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_FLAG_TC);
		__HAL_UART_CLEAR_FLAG(&uart->huart[chx],UART_IT_TC);
	}
	else
	{
	
		if (__HAL_UART_GET_FLAG(&(uart->huart[chx]), UART_FLAG_ORE) != RESET)
		{
				__HAL_UART_CLEAR_OREFLAG(&uart->huart[chx]);
		}
		if (__HAL_UART_GET_FLAG(&(uart->huart[chx]), UART_FLAG_NE) != RESET)
		{
				__HAL_UART_CLEAR_NEFLAG(&uart->huart[chx]);
		}
		if (__HAL_UART_GET_FLAG(&(uart->huart[chx]), UART_FLAG_FE) != RESET)
		{
				__HAL_UART_CLEAR_FEFLAG(&uart->huart[chx]);
		}
		if (__HAL_UART_GET_FLAG(&(uart->huart[chx]), UART_FLAG_PE) != RESET)
		{
				__HAL_UART_CLEAR_PEFLAG(&uart->huart[chx]);
		}
	}
				
	HAL_UART_IRQHandler(&uart->huart[chx]);
}

void USART1_IRQHandler(void)
{	
	uart_isr(uart_ch1);
}

void USART2_IRQHandler(void)
{	
	uart_isr(uart_ch2);
}

void USART3_IRQHandler(void)
{	
	uart_isr(uart_ch3);
}


static uint8_t stm32_putc(uart_chx_e chx,fifo_t *fifo)
{
	uint8_t ch = 0;
	stm_uart_t *uart = &stm_uart_dev;
	
	uint8_t can_tx = read_fifo(fifo,&ch);
	
	if(can_tx)	
	{
		uart->huart[chx].Instance->DR = ch;
		while (__HAL_UART_GET_FLAG(&(uart->huart[chx]), UART_FLAG_TC) == RESET);
	}

	return 0;
}

static uint8_t stm32_getc(fifo_t *fifo, uint8_t ch)
{
	return write_fifo(fifo,ch);
}

void finsh_uart_writes(uart_chx_e chx, uint8_t *wbuf,uint16_t size)
{
	if(!wbuf || !size) return;
	
	stm_uart_t *uart = &stm_uart_dev;
	for(uint16_t i=0;i<size;i++)
	{		
		write_fifo(&uart->sfifo[chx],wbuf[i]);
	}
	
	__HAL_UART_ENABLE_IT(&uart->huart[chx],UART_IT_TXE);
}

uint32_t finsh_uart_reads(uart_chx_e chx, uint8_t *rbuf,uint16_t size)
{
	if(!rbuf || !size) return 0;
	
	stm_uart_t *uart = &stm_uart_dev;
	uint16_t len = 0;
	for(uint16_t i=0;i<size;i++)
	{		
		uint8_t read_sta = read_fifo(&uart->rfifo[chx],&rbuf[i]);
		if(read_sta == 0) break;
		
		len++;
	}
	
	return len;
}

void finsh_poll(uint32_t poll_times)
{
	if(poll_times <= 0) poll_times = 5;//5ms
	static uint32_t tick = 0;
	if(!tick) tick = HAL_GetTick();
	
	if(tick - HAL_GetTick() > poll_times)
	{
		tick = HAL_GetTick();
		usmart_dev.scan();
	}
}


void finsh_uart_init(uart_chx_e chx,struct uart_configure cfg)
{
	static uint8_t init_ok = 0;
	if(!init_ok)
	{
		memset(&stm_uart_dev,0,sizeof(stm_uart_dev));	
		usmart_dev.init(72);
		init_ok = 1;
	}
	
	stm_uart_t *uart = &stm_uart_dev;
	
	uint16_t tx_size;
	uint16_t rx_size;
	tx_size = cfg.tx_size;
	rx_size = cfg.rx_size;
	
	if(uart->tx_buf[chx] == NULL) 
		uart->tx_buf[chx] = malloc(tx_size);
	if(uart->rx_buf[chx] == NULL) 
		uart->rx_buf[chx] = malloc(rx_size);
	
	fifo_init( &uart->sfifo[chx] ,uart->tx_buf[chx],tx_size);
	fifo_init( &uart->rfifo[chx] ,uart->rx_buf[chx],rx_size);
	
	stm32_uart_init(chx,cfg);

	printf("\r\nuart[%d] init successful.\r\n",chx+1);
}



